/*
 * @(#)XfeditRuleistFreeModel.java        1.0 2000/05/09
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

package xfuzzy.xfedit;

import xfuzzy.lang.*;
import xfuzzy.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.awt.*;

/**
 * Modelo de la tabla para la representaci�n de una lista de reglas
 * en formato libre
 * 
 * @author Francisco Jos� Moreno Velo
 * @modified Pablo Martin Mu�oz
 *
 */
public class XfeditRuleListFreeModel extends AbstractTableModel
implements TableCellRenderer {

	/**
	 * C�digo asociado a la clase serializable
	 */
	private static final long serialVersionUID = 95505666603032L;

	//----------------------------------------------------------------------------//
	//                            MIEMBROS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Etiqueta para representar las celdas de las columnas 0, 2 y 5
	 */
	private XLabel label;
	
	/**
	 * Etiqueta para representar las celdas de las columnas 1, 3, y 6
	 */
	private JLabel text;
	
	/**
	 * Valor del grado de certeza de cada regla
	 */
	//private double[] degree;
	
	/**
	 * Editor del antecedente de cada regla
	 */
	private XfeditRuleListFreeAntec[] premise;
	
	/**
	 * Editor del consecuente de cada regla
	 */
	private XfeditRuleListFreeConseq[] conclusion;
	
	/**
	 * Panel de edici�n de la lista de reglas en formato libre
	 */
	private XfeditRuleListFreePanel panel;

	//----------------------------------------------------------------------------//
	//                                CONSTRUCTOR                                 //
	//----------------------------------------------------------------------------//

	/**
	 * Constructor
	 */
	public XfeditRuleListFreeModel(XfeditRuleListFreePanel panel, RuleList copy) {
		super();
		this.panel = panel;
		initialize(copy);
	}

	//----------------------------------------------------------------------------//
	//                             M�TODOS P�BLICOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Obtiene el n�mero de columnas de la tabla
	 */
	public int getColumnCount() {
		return 5;
	}

	/**
	 * Obtiene el n�mero de filas (reglas) de la tabla
	 */
	public int getRowCount() {
		return this.premise.length;
	}

	/**
	 * Obtiene un elemento de la tabla
	 */
	public Object getValueAt(int row, int column) {
		int rowcount = premise.length;
		if(column == 0) {
			if(row < rowcount-2) return ""+row;
			if(row == rowcount-2) return "*";
			if(row == rowcount-1) return ""+(rowcount-2);
		}
		if(column == 1) {
			if(row == 0) return "if";
			if(row <rowcount-2) return "elseif";
			if(row == rowcount-2) return "";
			if(row == rowcount-1) return "else";
		}
		if(column == 2) {
			if(row < rowcount-2) return premise[row].toString();
			else return "";
		}
		if(column == 3) {
			if(row == rowcount-2) return "";
			else return "->";
		}
		if(column == 4) {
			if(row == rowcount-2) return "";
			else return conclusion[row];
		}
		return "";
	}

	/**
	 * Asigna el valor a un elemento de la tabla
	 */
	public void setValueAt(Object value, int row, int column) {
		if(row == premise.length-2 && column == 2) addRow();
		fireTableCellUpdated(row, column);
	}

	/**
	 * Obtiene las reglas representadas en la tabla
	 */
	public boolean getRules(RuleList copy) {
		copy.removeAllRules();
		int rowcount = premise.length;

		for(int i=0; i<rowcount-2; i++) {
			if(premise[i].isIncomplete()) return false;
		}	
		for(int i=0; i<rowcount-2; i++) {
			if(conclusion[i].isIncomplete()) return false;
		}
		if(conclusion[rowcount-1].isIncomplete()) return false;
	

		for(int i=0; i<rowcount-2; i++) {
			int rulekind = (i==0? RL_Rule.FIRST_RULE: RL_Rule.INNER_RULE);
			RL_Rule newrule = new RL_Rule(premise[i].getAntecedent(), rulekind);
			Conclusion conc[] = conclusion[i].getConsequents();
			for(int j=0; j<conc.length; j++) newrule.add(conc[j]);
			copy.addRule(newrule);
		}
		
		RL_Rule lastrule = new RL_Rule(null,RL_Rule.LAST_RULE);
		Conclusion conc[] = conclusion[rowcount-1].getConsequents();
		for(int j=0; j<conc.length; j++) lastrule.add(conc[j]);
		copy.addRule(lastrule);
		
		return true;
	}

	/**
	 * Obtiene los t�tulos de las columnas de la tabla
	 */
	public String getColumnName(int column) {
		if(column == 0) return "Rule";
		if(column == 1) return "";
		if(column == 2) return "Premise";
		if(column == 3) return "";
		if(column == 4) return "Conclusion";
		return "";
	}

	/**
	 * Obtiene el editor de una celda de la tabla
	 */
	public TableCellEditor getEditor(int row, int column) {
		if(column == 2) return premise[row];
		if(column == 4) return conclusion[row];
		return null;
	}

	/**
	 * Estudia si la celda es editable
	 */
	public boolean isCellEditable(int row, int column) {
		if(column == 2 && row < premise.length-1) return true;
		if(column == 4 && row < premise.length-2) return true;
		if(column == 4 && row == premise.length-1) return true;
		return false;
	}

	/**
	 * Obtiene el componente que representa cada celda
	 */
	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		if(column == 0 || column == 1 || column == 3)
		{ label.setText(value.toString()); return label; }
		if(isSelected) {
			text.setForeground(table.getSelectionForeground());
			text.setBackground(XConstants.textselectedbg);
		} else {
			text.setForeground(Color.black);
			text.setBackground(XConstants.textbackground);
		}
		text.setText(value.toString());
		return text;
	}

	/**
	 * Ejecuta una accion sobre el modelo
	 */
	public void modelAction(int row,int kind) {
		if(kind == -2) conclusion[row].conclusionAdd();
		else premise[row].action(kind);
	}

	/**
	 * Modifica la variable y MF del antecedente seleccionado
	 */
	public void changePremise(int row, Variable var, LinguisticLabel pmf) {
		premise[row].setVariable(var);
		premise[row].setMembershipFunction(pmf);
	}

	/**
	 * Modifica la variable y MF del consecuente seleccionado
	 */
	public void changeConclusion(int row, Variable var, LinguisticLabel pmf) {
		conclusion[row].setVariable(var);
		conclusion[row].setMembershipFunction(pmf);
	}

	/**
	 * Elimina una fila (regla) de la tabla
	 */
	public void removeRow(int row) {
		int rowcount = premise.length;
		XfeditRuleListFreeAntec auxpm[];
		auxpm = new XfeditRuleListFreeAntec[rowcount-1];
		System.arraycopy(premise,0,auxpm,0,row);
		System.arraycopy(premise,row+1,auxpm,row,rowcount-row-1);
		premise = auxpm;

		XfeditRuleListFreeConseq auxcn[];
		auxcn = new XfeditRuleListFreeConseq[rowcount-1];
		System.arraycopy(conclusion,0,auxcn,0,row);
		System.arraycopy(conclusion,row+1,auxcn,row,rowcount-row-1);
		conclusion = auxcn;

		fireTableChanged(new TableModelEvent(this, row, row,
				TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE));
	}

	//----------------------------------------------------------------------------//
	//                             M�TODOS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Inicializa el contenido de la tabla
	 */
	private void initialize(RuleList copy) {
		label = new XLabel("");
		label.setLabelFont(XConstants.textfont);
		text = new JLabel("");
		text.setFont(XConstants.textfont);
		text.setOpaque(true);
		RL_Rule[] rule = copy.getRules();
		if (rule.length == 0) {
			//RuleList vacio
			premise = new XfeditRuleListFreeAntec[3];
			conclusion = new XfeditRuleListFreeConseq[3];
			for(int i=0;i<3;i++) {
				if (i!=2) {
					premise[i] = new XfeditRuleListFreeAntec(panel,null);
				}
				else {
					premise[i] = null;
				}
				conclusion[i] = new XfeditRuleListFreeConseq(panel,new Conclusion[0]);
			}
		}
		else {
			//RuleList lleno
			premise = new XfeditRuleListFreeAntec[rule.length+1];
			conclusion = new XfeditRuleListFreeConseq[rule.length+1];
			for(int i=0; i<rule.length-1; i++) {
				RL_Rule ruleclone = (RL_Rule) rule[i].clone(copy);
				Conclusion[] conclone = ruleclone.getConclusions();
				premise[i] = new XfeditRuleListFreeAntec(panel,ruleclone.getPremise());
				conclusion[i] = new XfeditRuleListFreeConseq(panel,conclone);
			}
			RL_Rule lastruleclone = (RL_Rule) rule[rule.length-1].clone(copy);
			conclusion[rule.length] = new XfeditRuleListFreeConseq(panel,lastruleclone.getConclusions());
		}
	}

	/**
	 * A�ade una fila (regla) a la tabla
	 */
	private void addRow() {
		int rowcount = premise.length;
		
		XfeditRuleListFreeAntec auxpm[];
		auxpm = new XfeditRuleListFreeAntec[rowcount+1];
		System.arraycopy(premise,0,auxpm,0,rowcount-2);
		auxpm[rowcount-2] = new XfeditRuleListFreeAntec(panel,null);
		auxpm[rowcount-1] = premise[rowcount-2];
		auxpm[rowcount] = premise[rowcount-1];
		premise = auxpm;

		XfeditRuleListFreeConseq auxcn[];
		auxcn = new XfeditRuleListFreeConseq[rowcount+1];
		System.arraycopy(conclusion,0,auxcn,0,rowcount-2);
		auxcn[rowcount-2] = new XfeditRuleListFreeConseq(panel,new Conclusion[0]);
		auxcn[rowcount-1] = conclusion[rowcount-2];
		auxcn[rowcount] = conclusion[rowcount-1];
		conclusion = auxcn;

		fireTableChanged(new TableModelEvent(this, rowcount+1, rowcount+1,
				TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
	}

}

